home *** CD-ROM | disk | FTP | other *** search
- /*
- * audio.cpp - Audio support
- *
- * Basilisk II (C) 1997-2001 Christian Bauer
- * Portions (C) 1997-1999 Marc Hellwig
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
- /*
- * SEE ALSO
- * Inside Macintosh: Sound, chapter 5 "Sound Components"
- */
-
- #include "sysdeps.h"
- #include "cpu_emulation.h"
- #include "macos_util.h"
- #include "emul_op.h"
- #include "main.h"
- #include "audio.h"
- #include "audio_defs.h"
-
- #define DEBUG 0
- #include "debug.h"
-
-
- // Global variables
- struct audio_status AudioStatus; // Current audio status (sample rate etc.)
- bool audio_open = false; // Flag: audio is initialized and ready
- int audio_frames_per_block; // Number of audio frames per block
- uint32 audio_component_flags; // Component feature flags
- uint32 audio_data = 0; // Mac address of global data area
- static int open_count = 0; // Open/close nesting count
-
- bool AudioAvailable = false; // Flag: audio output available (from the software point of view)
-
-
- /*
- * Reset audio emulation
- */
-
- void AudioReset(void)
- {
- audio_data = 0;
- }
-
-
- /*
- * Get audio info
- */
-
- static int32 AudioGetInfo(uint32 infoPtr, uint32 selector, uint32 sourceID)
- {
- D(bug(" AudioGetInfo %c%c%c%c, infoPtr %08lx, source ID %08lx\n", selector >> 24, (selector >> 16) & 0xff, (selector >> 8) & 0xff, selector & 0xff, infoPtr, sourceID));
- M68kRegisters r;
- int i;
-
- switch (selector) {
- case siSampleSize:
- WriteMacInt16(infoPtr, AudioStatus.sample_size);
- break;
-
- case siSampleSizeAvailable: {
- r.d[0] = audio_num_sample_sizes * 2;
- Execute68kTrap(0xa122, &r); // NewHandle()
- uint32 h = r.a[0];
- if (h == 0)
- return memFullErr;
- WriteMacInt16(infoPtr + sil_count, audio_num_sample_sizes);
- WriteMacInt32(infoPtr + sil_infoHandle, h);
- uint32 sp = ReadMacInt32(h);
- for (i=0; i<audio_num_sample_sizes; i++)
- WriteMacInt16(sp + i*2, audio_sample_sizes[i]);
- break;
- }
-
- case siNumberChannels:
- WriteMacInt16(infoPtr, AudioStatus.channels);
- break;
-
- case siChannelAvailable: {
- r.d[0] = audio_num_channel_counts * 2;
- Execute68kTrap(0xa122, &r); // NewHandle()
- uint32 h = r.a[0];
- if (h == 0)
- return memFullErr;
- WriteMacInt16(infoPtr + sil_count, audio_num_channel_counts);
- WriteMacInt32(infoPtr + sil_infoHandle, h);
- uint32 sp = ReadMacInt32(h);
- for (i=0; i<audio_num_channel_counts; i++)
- WriteMacInt16(sp + i*2, audio_channel_counts[i]);
- break;
- }
-
- case siSampleRate:
- WriteMacInt32(infoPtr, AudioStatus.sample_rate);
- break;
-
- case siSampleRateAvailable: {
- r.d[0] = audio_num_sample_rates * 4;
- Execute68kTrap(0xa122, &r); // NewHandle()
- uint32 h = r.a[0];
- if (h == 0)
- return memFullErr;
- WriteMacInt16(infoPtr + sil_count, audio_num_sample_rates);
- WriteMacInt32(infoPtr + sil_infoHandle, h);
- uint32 lp = ReadMacInt32(h);
- for (i=0; i<audio_num_sample_rates; i++)
- WriteMacInt32(lp + i*4, audio_sample_rates[i]);
- break;
- }
-
- case siSpeakerMute:
- WriteMacInt16(infoPtr, audio_get_speaker_mute());
- break;
-
- case siSpeakerVolume:
- WriteMacInt32(infoPtr, audio_get_speaker_volume());
- break;
-
- case siHeadphoneMute:
- WriteMacInt16(infoPtr, 0);
- break;
-
- case siHeadphoneVolume:
- WriteMacInt32(infoPtr, 0x01000100);
- break;
-
- case siHeadphoneVolumeSteps:
- WriteMacInt16(infoPtr, 13);
- break;
-
- case siHardwareMute:
- WriteMacInt16(infoPtr, audio_get_main_mute());
- break;
-
- case siHardwareVolume:
- WriteMacInt32(infoPtr, audio_get_main_volume());
- break;
-
- case siHardwareVolumeSteps:
- WriteMacInt16(infoPtr, 13);
- break;
-
- case siHardwareBusy:
- WriteMacInt16(infoPtr, AudioStatus.num_sources != 0);
- break;
-
- default: // Delegate to Apple Mixer
- if (AudioStatus.mixer == 0)
- return badComponentSelector;
- M68kRegisters r;
- r.a[0] = infoPtr;
- r.d[0] = selector;
- r.a[1] = sourceID;
- r.a[2] = AudioStatus.mixer;
- Execute68k(audio_data + adatGetInfo, &r);
- D(bug(" delegated to Apple Mixer, returns %08lx\n", r.d[0]));
- return r.d[0];
- }
- return noErr;
- }
-
-
- /*
- * Set audio info
- */
-
- static int32 AudioSetInfo(uint32 infoPtr, uint32 selector, uint32 sourceID)
- {
- D(bug(" AudioSetInfo %c%c%c%c, infoPtr %08lx, source ID %08lx\n", selector >> 24, (selector >> 16) & 0xff, (selector >> 8) & 0xff, selector & 0xff, infoPtr, sourceID));
- M68kRegisters r;
- int i;
-
- switch (selector) {
- case siSampleSize:
- D(bug(" set sample size %08lx\n", infoPtr));
- if (AudioStatus.num_sources)
- return siDeviceBusyErr;
- for (i=0; i<audio_num_sample_sizes; i++)
- if (audio_sample_sizes[i] == infoPtr) {
- audio_set_sample_size(i);
- return noErr;
- }
- return siInvalidSampleSize;
-
- case siSampleRate:
- D(bug(" set sample rate %08lx\n", infoPtr));
- if (AudioStatus.num_sources)
- return siDeviceBusyErr;
- for (i=0; i<audio_num_sample_rates; i++)
- if (audio_sample_rates[i] == infoPtr) {
- audio_set_sample_rate(i);
- return noErr;
- }
- return siInvalidSampleRate;
-
- case siNumberChannels:
- D(bug(" set number of channels %08lx\n", infoPtr));
- if (AudioStatus.num_sources)
- return siDeviceBusyErr;
- for (i=0; i<audio_num_channel_counts; i++)
- if (audio_channel_counts[i] == infoPtr) {
- audio_set_channels(i);
- return noErr;
- }
- return badChannel;
-
- case siSpeakerMute:
- audio_set_speaker_mute((uint16)infoPtr);
- break;
-
- case siSpeakerVolume:
- D(bug(" set speaker volume %08lx\n", infoPtr));
- audio_set_speaker_volume(infoPtr);
- break;
-
- case siHeadphoneMute:
- case siHeadphoneVolume:
- break;
-
- case siHardwareMute:
- audio_set_main_mute((uint16)infoPtr);
- break;
-
- case siHardwareVolume:
- D(bug(" set hardware volume %08lx\n", infoPtr));
- audio_set_main_volume(infoPtr);
- break;
-
- default: // Delegate to Apple Mixer
- if (AudioStatus.mixer == 0)
- return badComponentSelector;
- r.a[0] = infoPtr;
- r.d[0] = selector;
- r.a[1] = sourceID;
- r.a[2] = AudioStatus.mixer;
- Execute68k(audio_data + adatSetInfo, &r);
- D(bug(" delegated to Apple Mixer, returns %08lx\n", r.d[0]));
- return r.d[0];
- }
- return noErr;
- }
-
-
- /*
- * Sound output component dispatch
- */
-
- int32 AudioDispatch(uint32 params, uint32 globals)
- {
- D(bug("AudioDispatch params %08lx (size %d), what %d\n", params, ReadMacInt8(params + cp_paramSize), (int16)ReadMacInt16(params + cp_what)));
- M68kRegisters r;
- uint32 p = params + cp_params;
-
- switch ((int16)ReadMacInt16(params + cp_what)) {
- // Basic component functions
- case kComponentOpenSelect:
- if (audio_data == 0) {
-
- // Allocate global data area
- r.d[0] = SIZEOF_adat;
- Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
- if (r.a[0] == 0)
- return memFullErr;
- audio_data = r.a[0];
- D(bug(" global data at %08lx\n", audio_data));
-
- // Put in 68k routines
- int p = audio_data + adatDelegateCall;
- WriteMacInt16(p, 0x598f); p += 2; // subq.l #4,sp
- WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
- WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
- WriteMacInt16(p, 0x7024); p += 2; // moveq #$24,d0
- WriteMacInt16(p, 0xa82a); p += 2; // ComponentDispatch
- WriteMacInt16(p, 0x201f); p += 2; // move.l (sp)+,d0
- WriteMacInt16(p, M68K_RTS); p += 2; // rts
- if (p - audio_data != adatOpenMixer)
- goto adat_error;
- WriteMacInt16(p, 0x558f); p += 2; // subq.l #2,sp
- WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
- WriteMacInt16(p, 0x2f00); p += 2; // move.l d0,-(sp)
- WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
- WriteMacInt16(p, 0x203c); p += 2; // move.l #$06140018,d0
- WriteMacInt32(p, 0x06140018); p+= 4;
- WriteMacInt16(p, 0xa800); p += 2; // SoundDispatch
- WriteMacInt16(p, 0x301f); p += 2; // move.w (sp)+,d0
- WriteMacInt16(p, 0x48c0); p += 2; // ext.l d0
- WriteMacInt16(p, M68K_RTS); p += 2; // rts
- if (p - audio_data != adatCloseMixer)
- goto adat_error;
- WriteMacInt16(p, 0x558f); p += 2; // subq.l #2,sp
- WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
- WriteMacInt16(p, 0x203c); p += 2; // move.l #$02180018,d0
- WriteMacInt32(p, 0x02180018); p+= 4;
- WriteMacInt16(p, 0xa800); p += 2; // SoundDispatch
- WriteMacInt16(p, 0x301f); p += 2; // move.w (sp)+,d0
- WriteMacInt16(p, 0x48c0); p += 2; // ext.l d0
- WriteMacInt16(p, M68K_RTS); p += 2; // rts
- if (p - audio_data != adatGetInfo)
- goto adat_error;
- WriteMacInt16(p, 0x598f); p += 2; // subq.l #4,sp
- WriteMacInt16(p, 0x2f0a); p += 2; // move.l a2,-(sp)
- WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
- WriteMacInt16(p, 0x2f00); p += 2; // move.l d0,-(sp)
- WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
- WriteMacInt16(p, 0x2f3c); p += 2; // move.l #$000c0103,-(sp)
- WriteMacInt32(p, 0x000c0103); p+= 4;
- WriteMacInt16(p, 0x7000); p += 2; // moveq #0,d0
- WriteMacInt16(p, 0xa82a); p += 2; // ComponentDispatch
- WriteMacInt16(p, 0x201f); p += 2; // move.l (sp)+,d0
- WriteMacInt16(p, M68K_RTS); p += 2; // rts
- if (p - audio_data != adatSetInfo)
- goto adat_error;
- WriteMacInt16(p, 0x598f); p += 2; // subq.l #4,sp
- WriteMacInt16(p, 0x2f0a); p += 2; // move.l a2,-(sp)
- WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
- WriteMacInt16(p, 0x2f00); p += 2; // move.l d0,-(sp)
- WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
- WriteMacInt16(p, 0x2f3c); p += 2; // move.l #$000c0104,-(sp)
- WriteMacInt32(p, 0x000c0104); p+= 4;
- WriteMacInt16(p, 0x7000); p += 2; // moveq #0,d0
- WriteMacInt16(p, 0xa82a); p += 2; // ComponentDispatch
- WriteMacInt16(p, 0x201f); p += 2; // move.l (sp)+,d0
- WriteMacInt16(p, M68K_RTS); p += 2; // rts
- if (p - audio_data != adatPlaySourceBuffer)
- goto adat_error;
- WriteMacInt16(p, 0x598f); p += 2; // subq.l #4,sp
- WriteMacInt16(p, 0x2f0a); p += 2; // move.l a2,-(sp)
- WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
- WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
- WriteMacInt16(p, 0x2f00); p += 2; // move.l d0,-(sp)
- WriteMacInt16(p, 0x2f3c); p += 2; // move.l #$000c0108,-(sp)
- WriteMacInt32(p, 0x000c0108); p+= 4;
- WriteMacInt16(p, 0x7000); p += 2; // moveq #0,d0
- WriteMacInt16(p, 0xa82a); p += 2; // ComponentDispatch
- WriteMacInt16(p, 0x201f); p += 2; // move.l (sp)+,d0
- WriteMacInt16(p, M68K_RTS); p += 2; // rts
- if (p - audio_data != adatGetSourceData)
- goto adat_error;
- WriteMacInt16(p, 0x598f); p += 2; // subq.l #4,sp
- WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
- WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
- WriteMacInt16(p, 0x2f3c); p += 2; // move.l #$00040004,-(sp)
- WriteMacInt32(p, 0x00040004); p+= 4;
- WriteMacInt16(p, 0x7000); p += 2; // moveq #0,d0
- WriteMacInt16(p, 0xa82a); p += 2; // ComponentDispatch
- WriteMacInt16(p, 0x201f); p += 2; // move.l (sp)+,d0
- WriteMacInt16(p, M68K_RTS); p += 2; // rts
- if (p - audio_data != adatData)
- goto adat_error;
- }
- AudioAvailable = true;
- if (open_count == 0)
- audio_enter_stream();
- open_count++;
- return noErr;
-
- adat_error: printf("FATAL: audio component data block initialization error\n");
- QuitEmulator();
- return openErr;
-
- case kComponentCanDoSelect:
- case kComponentRegisterSelect:
- return noErr;
-
- case kComponentVersionSelect:
- return 0x00010003;
-
- case kComponentCloseSelect:
- open_count--;
- if (open_count == 0) {
- if (AudioStatus.mixer) {
- // Close Apple Mixer
- r.a[0] = AudioStatus.mixer;
- Execute68k(audio_data + adatCloseMixer, &r);
- AudioStatus.mixer = 0;
- return r.d[0];
- }
- AudioStatus.num_sources = 0;
- audio_exit_stream();
- }
- return noErr;
-
- // Sound component functions
- case kSoundComponentInitOutputDeviceSelect:
- D(bug(" InitOutputDevice\n"));
- if (!audio_open)
- return noHardwareErr;
- if (AudioStatus.mixer)
- return noErr;
-
- // Init sound component data
- WriteMacInt32(audio_data + adatData + scd_flags, 0);
- WriteMacInt32(audio_data + adatData + scd_format, AudioStatus.sample_size == 16 ? FOURCC('t','w','o','s') : FOURCC('r','a','w',' '));
- WriteMacInt16(audio_data + adatData + scd_numChannels, AudioStatus.channels);
- WriteMacInt16(audio_data + adatData + scd_sampleSize, AudioStatus.sample_size);
- WriteMacInt32(audio_data + adatData + scd_sampleRate, AudioStatus.sample_rate);
- WriteMacInt32(audio_data + adatData + scd_sampleCount, audio_frames_per_block);
- WriteMacInt32(audio_data + adatData + scd_buffer, 0);
- WriteMacInt32(audio_data + adatData + scd_reserved, 0);
- WriteMacInt32(audio_data + adatStreamInfo, 0);
-
- // Open Apple Mixer
- r.a[0] = audio_data + adatMixer;
- r.d[0] = 0;
- r.a[1] = audio_data + adatData;
- Execute68k(audio_data + adatOpenMixer, &r);
- AudioStatus.mixer = ReadMacInt32(audio_data + adatMixer);
- D(bug(" OpenMixer() returns %08lx, mixer %08lx\n", r.d[0], AudioStatus.mixer));
- return r.d[0];
-
- case kSoundComponentAddSourceSelect:
- D(bug(" AddSource\n"));
- AudioStatus.num_sources++;
- goto delegate;
-
- case kSoundComponentRemoveSourceSelect:
- D(bug(" RemoveSource\n"));
- AudioStatus.num_sources--;
- goto delegate;
-
- case kSoundComponentStopSourceSelect:
- D(bug(" StopSource\n"));
- goto delegate;
-
- case kSoundComponentPauseSourceSelect:
- D(bug(" PauseSource\n"));
- delegate: // Delegate call to Apple Mixer
- D(bug(" delegating call to Apple Mixer\n"));
- r.a[0] = AudioStatus.mixer;
- r.a[1] = params;
- Execute68k(audio_data + adatDelegateCall, &r);
- D(bug(" returns %08lx\n", r.d[0]));
- return r.d[0];
-
- case kSoundComponentStartSourceSelect:
- D(bug(" StartSource\n"));
- return noErr;
-
- case kSoundComponentGetInfoSelect:
- return AudioGetInfo(ReadMacInt32(p), ReadMacInt32(p + 4), ReadMacInt32(p + 8));
-
- case kSoundComponentSetInfoSelect:
- return AudioSetInfo(ReadMacInt32(p), ReadMacInt32(p + 4), ReadMacInt32(p + 8));
-
- case kSoundComponentPlaySourceBufferSelect:
- D(bug(" PlaySourceBuffer\n"));
- r.d[0] = ReadMacInt32(p);
- r.a[0] = ReadMacInt32(p + 4);
- r.a[1] = ReadMacInt32(p + 8);
- r.a[2] = AudioStatus.mixer;
- Execute68k(audio_data + adatPlaySourceBuffer, &r);
- D(bug(" returns %08lx\n", r.d[0]));
- return r.d[0];
-
- default:
- return badComponentSelector;
- }
- }
-
-
- /*
- * Sound input driver Open() routine
- */
-
- int16 SoundInOpen(uint32 pb, uint32 dce)
- {
- D(bug("SoundInOpen\n"));
- return noErr;
- }
-
-
- /*
- * Sound input driver Prime() routine
- */
-
- int16 SoundInPrime(uint32 pb, uint32 dce)
- {
- D(bug("SoundInPrime\n"));
- //!!
- return paramErr;
- }
-
-
- /*
- * Sound input driver Control() routine
- */
-
- int16 SoundInControl(uint32 pb, uint32 dce)
- {
- uint16 code = ReadMacInt16(pb + csCode);
- D(bug("SoundInControl %d\n", code));
-
- if (code == 1) {
- D(bug(" SoundInKillIO\n"));
- //!!
- return noErr;
- }
-
- if (code != 2)
- return -231; // siUnknownInfoType
-
- uint32 *param = (uint32 *)Mac2HostAddr(pb + csParam);
- uint32 selector = param[0];
- D(bug(" selector %c%c%c%c\n", selector >> 24, selector >> 16, selector >> 8, selector));
-
- switch (selector) {
- default:
- return -231; // siUnknownInfoType
- }
- }
-
-
- /*
- * Sound input driver Status() routine
- */
-
- int16 SoundInStatus(uint32 pb, uint32 dce)
- {
- uint16 code = ReadMacInt16(pb + csCode);
- D(bug("SoundInStatus %d\n", code));
- if (code != 2)
- return -231; // siUnknownInfoType
-
- uint32 *param = (uint32 *)Mac2HostAddr(pb + csParam);
- uint32 selector = param[0];
- D(bug(" selector %c%c%c%c\n", selector >> 24, selector >> 16, selector >> 8, selector));
- switch (selector) {
- #if 0
- case siDeviceName: {
- const char *str = GetString(STR_SOUND_IN_NAME);
- param[0] = 0;
- memcpy((void *)param[1], str, strlen(str));
- return noErr;
- }
-
- case siDeviceIcon: {
- M68kRegisters r;
- static const uint16 proc[] = {
- 0x558f, // subq.l #2,sp
- 0xa994, // CurResFile
- 0x4267, // clr.w -(sp)
- 0xa998, // UseResFile
- 0x598f, // subq.l #4,sp
- 0x4879, 0x4943, 0x4e23, // move.l #'ICN#',-(sp)
- 0x3f3c, 0xbf76, // move.w #-16522,-(sp)
- 0xa9a0, // GetResource
- 0x245f, // move.l (sp)+,a2
- 0xa998, // UseResFile
- 0x200a, // move.l a2,d0
- 0x6604, // bne 1
- 0x7000, // moveq #0,d0
- M68K_RTS,
- 0x2f0a, //1 move.l a2,-(sp)
- 0xa992, // DetachResource
- 0x204a, // move.l a2,a0
- 0xa04a, // HNoPurge
- 0x7001, // moveq #1,d0
- M68K_RTS
- };
- Execute68k((uint32)proc, &r);
- if (r.d[0]) {
- param[0] = 4; // Length of returned data
- param[1] = r.a[2]; // Handle to icon suite
- return noErr;
- } else
- return -192; // resNotFound
- }
- #endif
- default:
- return -231; // siUnknownInfoType
- }
- }
-
-
- /*
- * Sound input driver Close() routine
- */
-
- int16 SoundInClose(uint32 pb, uint32 dce)
- {
- D(bug("SoundInClose\n"));
- return noErr;
- }
-